package controller

// user_info_controller.go
// 与 User 相关的 handle func

import (
	"errors"
	"fmt"
	"gforum/model"
	"gforum/service"
	"gforum/utils"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"net/http"
	"time"
)

// CheckIn 完成用户签到，确保用户每天只签到一次
// 签到成功之后返回用户的 UserLevel JSON
func CheckIn(ctx *gin.Context) {
	username := ctx.MustGet("username").(string)

	userLevel, err := service.AddCheckInExp(username)
	switch {
	case errors.Is(err, service.ErrAlreadyCheckedIn):
		utils.BadRequest(ctx, err, "User can't check in twice a day")
		return
	case errors.Is(err, service.ErrRecordNotFound):
		utils.BadRequest(ctx, err, "User not found")
		return
	case err != nil:
		utils.InternalServerError(ctx, err, "Internal error in process check in")
		return
	}

	ctx.JSON(http.StatusOK, userLevel)
}

// GetMe 返回当前登录的用户的 User instance(基于 Authorization 中的 Header)
// 同时将 Password 置为一个随机值
func GetMe(ctx *gin.Context) {
	username := ctx.MustGet("username").(string)

	user, err := service.GetUser(username)
	if err != nil {
		utils.BadRequest(ctx, err, "User not found")
		return
	}

	// 用一个随机的字符串替代数据库中的 hashed Password，
	// 懒得改 API 和数据模型了，就这样吧🤗
	user.Password = fmt.Sprintf("%x", time.Now().UnixNano())[:8]

	ctx.JSON(http.StatusOK, user)
}

func UpdateInfo(ctx *gin.Context) {
	username := ctx.MustGet("username").(string)

	var userInfo model.UserInfo
	if err := ctx.ShouldBindJSON(&userInfo); err != nil {
		utils.BadRequest(ctx, err, "Invalid user info")
		return
	}

	updatedInfo, err := service.UpdateInfo(userInfo, username)
	switch {
	case errors.Is(err, service.ErrLackOfInput):
		utils.BadRequest(ctx, err, "Lack of input")
		return
	case errors.Is(err, service.ErrUnAuthorized):
		utils.Unauthorized(ctx, err, "Level not enough to update avatar")
		return
	case err != nil:
		utils.InternalServerError(ctx, err, "Internal error in updating info")
		return
	}

	ctx.JSON(http.StatusOK, updatedInfo)
}

// GetUserInfoByID 根据用户 ID 获取用户信息
func GetUserInfoByID(ctx *gin.Context) {
	userID := ctx.Param("id")
	if userID == "" {
		utils.BadRequest(ctx, errors.New("userInfo ID is required"), "User ID is required")
		return
	}

	userInfo, err := service.GetUserInfoByID(userID)
	if err != nil {
		utils.NotFound(ctx, err, "User not found")
		return
	}

	ctx.JSON(http.StatusOK, userInfo)
}

// GetUserLevelByID 根据用户 ID 获取用户等级
func GetUserLevelByID(ctx *gin.Context) {
	userID := ctx.Param("id")
	if userID == "" {
		utils.BadRequest(ctx, errors.New("userLevel ID is required"), "User ID is required")
		return
	}

	userLevel, err := service.GetUserLevelByID(userID)
	if err != nil {
		utils.NotFound(ctx, err, "User not found")
		return
	}

	ctx.JSON(http.StatusOK, userLevel)

}

// GetUserPostsByID 根据用户 ID 获取用户的所有帖子
func GetUserPostsByID(ctx *gin.Context) {
	userID := ctx.Param("id")
	if userID == "" {
		utils.BadRequest(ctx, errors.New("user ID is required"), "User ID is required")
		return
	}

	var query model.Pagination
	if err := ctx.ShouldBindQuery(&query); err != nil {
		utils.InternalServerError(ctx, err, "Error in bind query")
	}
	query.Default()

	userPosts, err := service.GetUserPostsByID(userID, query)
	switch {
	case errors.Is(err, gorm.ErrRecordNotFound):
		utils.NotFound(ctx, err, "User not found")
		return
	case err != nil:
		utils.InternalServerError(ctx, err, "Error in getting user posts")
		return
	}

	total, err := service.GetTotalSize(userID, &model.Post{})
	if err != nil {
		utils.InternalServerError(ctx, err, "Error in getting total size")
		return
	}

	totalPages := service.GetTotalPage(query.Size, total)

	ctx.JSON(http.StatusOK, gin.H{
		"page":       query.Page,
		"size":       len(*userPosts),
		"total":      total,
		"totalPages": totalPages,
		"posts":      userPosts,
	})
}

// GetUserCommentsByID 根据用户 ID 获取用户的所有评论
//
// 请求示例：GET /api/users/1/comments?page=1&size=7
//
// 请求参数:
//   - page: 页码，默认为 1
//   - size: 每页数量，默认为 7
func GetUserCommentsByID(ctx *gin.Context) {
	userID := ctx.Param("id")
	if userID == "" {
		utils.BadRequest(ctx, errors.New("user ID is required"), "User ID is required")
		return
	}

	var query model.Pagination
	if err := ctx.ShouldBindQuery(&query); err != nil {
		utils.InternalServerError(ctx, err, "Error in bind query")
	}
	query.Default()

	userComments, err := service.GetUserCommentsByID(userID, query)
	if err != nil {
		utils.InternalServerError(ctx, err, "Error in getting user comments")
		return
	}

	total, err := service.GetTotalCommentSize(userID, &model.Comment{})
	if err != nil {
		utils.InternalServerError(ctx, err, "Error in getting total size")
		return
	}

	totalPages := service.GetTotalPage(query.Size, total)

	ctx.JSON(http.StatusOK, gin.H{
		"page":       query.Page,
		"size":       len(*userComments),
		"total":      total,
		"totalPages": totalPages,
		"posts":      userComments,
	})
}
